package com.sailors.common.task.sdk.core.handle.factory;

import com.alibaba.fastjson.JSON;
import com.sailors.common.task.sdk.core.constants.enums.TaskAsyncEnum;
import com.sailors.common.task.sdk.core.handle.AbstractCommonTaskHandler;
import com.sailors.common.task.sdk.core.handle.worker.TaskContainer;
import com.sailors.common.task.sdk.core.model.FileTaskAsyncUploadCreateDto;
import com.sailors.common.task.sdk.core.model.FileTaskCreateDto;
import com.yomahub.tlog.core.thread.TLogInheritableTask;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Supplier;

/**
 * File task template handler
 *
 * @description: 模板文件任务执行类
 * @author: cyj
 * @date 2022 -11-25 14:51:47
 */
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class FileTaskTemplateHandler extends AbstractCommonTaskHandler {

    private volatile static FileTaskTemplateHandler fileTaskTemplateHandler;

    protected static FileTaskTemplateHandler getSingleton() {
        if (fileTaskTemplateHandler == null) {
            synchronized (FileTaskTemplateHandler.class) {
                if (fileTaskTemplateHandler == null) {
                    fileTaskTemplateHandler = new FileTaskTemplateHandler();
                }
            }
        }
        return fileTaskTemplateHandler;
    }

    private static final ExecutorService threadPool = Executors.newCachedThreadPool();

    /**
     * 创建执行任务（模板方法）, 在supplier.get() 具体实现里面，使用方需要 ：
     * 1.自己同步通知sdk任务进度（TaskContainer.refreshProcess())
     * 2.通知sdk任务结果，成功（refreshProcess.refreshProcess() 100 进度）, 失败(TaskContainer.faild())
     * @param fileTaskAsyncUploadCreateDto
     * @param supplier
     * @param <T>
     * @return
     * @see com.sailors.common.task.sdk.core.handle.worker.TaskContainer
     */
    public <T> Long executeAsyncUploadFileTask(FileTaskAsyncUploadCreateDto fileTaskAsyncUploadCreateDto, Supplier<T> supplier) {
        FileTaskCreateDto fileTaskCreateDto = JSON.parseObject(JSON.toJSONString(fileTaskAsyncUploadCreateDto), FileTaskCreateDto.class);
        fileTaskCreateDto.setAsync(TaskAsyncEnum.YES.code);
        Long taskId = Optional.ofNullable(HandlerFactory.getInstance(FileTaskHandler.class).createTask(fileTaskCreateDto))
                .orElseThrow(() -> new RuntimeException("文件任务创建失败！"));
        threadPool.submit(new TLogInheritableTask() {
            @Override
            public void runTask() {
                {
                    try {
                        TaskContainer.setTaskId(taskId);
                        supplier.get();
                    } catch (Exception e) {
                        log.error(e.getMessage(), e);
                    } finally {
                        TaskContainer.removeTaskId();
                    }
                }
            }
        });
        return taskId;
    }

    /**
     * 限制创建执行任务，限制单机按bussinessName只能最多有limit个任务在执行
     * 创建执行任务（模板方法）, 在supplier.get() 具体实现里面，使用方需要 ：
     * 1.自己同步通知sdk任务进度（TaskContainer.refreshProcess())
     * 2.通知sdk任务结果，成功（TaskContainer.refreshProcess() 100 进度）, 失败(TaskContainer.faild())
     * @param fileTaskAsyncUploadCreateDto
     * @param supplier
     * @param <T>
     * @return throw new RuntimeException("此业务进行了并行任务限制，当前系统节点有：" + limit + " 个此类型任务正在进行，请稍后重试")
     * @see com.sailors.common.task.sdk.core.handle.worker.TaskContainer
     */
    public <T> Long executeAsyncUploadFileTask(FileTaskAsyncUploadCreateDto fileTaskAsyncUploadCreateDto, Supplier<T> supplier, Integer limit) {

        TaskContainer.aquire(fileTaskAsyncUploadCreateDto.getBussinessName(), limit);

        FileTaskCreateDto fileTaskCreateDto = JSON.parseObject(JSON.toJSONString(fileTaskAsyncUploadCreateDto), FileTaskCreateDto.class);
        fileTaskCreateDto.setAsync(TaskAsyncEnum.YES.code);
        Long taskId = null;
        try {
            // 创建任务
            taskId = Optional.ofNullable(HandlerFactory.getInstance(FileTaskHandler.class).createTask(fileTaskCreateDto))
                    .orElseThrow(() -> new RuntimeException("文件任务创建失败！"));
        } catch (Exception e) {
            TaskContainer.release(fileTaskAsyncUploadCreateDto.getBussinessName());
            throw e;
        }
        Long executeId = taskId;
        // 执行业务
        threadPool.submit(new TLogInheritableTask() {
            @Override
            public void runTask() {
                try {
                    TaskContainer.setTaskId(executeId);
                    supplier.get();
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                } finally {
                    TaskContainer.removeTaskId();
                    TaskContainer.release(fileTaskAsyncUploadCreateDto.getBussinessName());
                }
            }
        });
        return taskId;
    }
}
